home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung CD 2 (Tewi)(1994).iso
/
doc
/
ems
/
docs
/
toolkit.txt
Wrap
Text File
|
1990-01-30
|
61KB
|
1,702 lines
The
EMS TOOLKIT
for C developers
Copyright (c) 1989 Intel Corporation. All rights reserved.
Intel Corporation, 5200 NE Elam Young Parkway, Hillsboro, OR 97124
First Edition December, 1989
DISCLAIMER
Intel Corporation assumes no responsibility for errors that may appear in
this manual. Nor does Intel make any commitment to update the
information contained in this manual.
Intel and Above are trademarks of Intel Corporation.
LIMITED WARRANTY
Intel Corporation excludes any and all implied warranties, including
warranties of merchantability and fitness for a particular purpose. Intel
makes no warranty of representation, either express or implied, with
respect to this software, its quality, performance, merchantability, or
fitness for a particular purpose. Intel shall not have any liability for
special, incidental, or consequential damages arising out of or resulting
from the use or modification of this software. This software is provided as
is.
USE OF PROGRAM PRODUCT You may use the Program Product on any one IBM or
compatible personal computer, and copy the Object Code into any
machine-readable form for your use of the Program Product; You may modify
the Program Product material and/or merge or incorporate it into any
general use software program of your development except for a utility
program of similar nature to the Program Product. You may freely reproduce
any such program of your development; however, the merged or incorporated
part of the Program Product will continue to be subject to all other
provisions of this agreement.
CONTENTS
CHAPTER 1. GETTING STARTED
How to use this book 1-2
What's on the disks? 1-3
Which library should I use? 1-5
Requirements 1-7
Installing the software 1-7
CHAPTER 2. MEMLIB: LIBRARY FOR C DEVELOPERS
Compiling and linking MEMLIB 2-3
Suggested sequence for using MEMLIB functions 2-4
MEMLIB functions list 2-5 -- 2-31
CHAPTER 3. EMMLIB: LIBRARY FOR ASSEMBLY LANGUAGE AND C DEVELOPERS
EMMLIB functions grouped by operation 3-3
EMMLIB functions in alphabetical order 3-7
APPENDIX A. EXAMPLE PROGRAM
APPENDIX B. ERROR MESSAGES
APPENDIX C. TECHNICAL INFORMATION ABOUT MEMLIB
How MEMLIB provides access to expanded memory C-1
How MEMLIB keeps track of expanded memory C-2
How MEMLIB allocates expanded memory C-2
Algorithms C-4
Chapter 1
GETTING STARTED
This manual describes the toolkit for the Lotus-Intel-Microsoft Expanded
Memory Specification (EMS). The toolkit offers experienced Microsoft C
developers a quick and easy way to use expanded memory in their application
programs.
If you are writing programs in some other Microsoft language (Fortran,
Pascal, etc.), you may still be able to use the toolkit. Read the
mixed-language programming section in the Microsoft manual to find out how
tomake calls to C from your language.
The toolkit includes the following libraries:
MEMLIB A set of C functions that perform the "housekeeping"
necessary to access and store data in expanded memory. When you
use MEMLIB, you won't need to worry about page frame size,
16K-byte boundaries, or interfacing with an assembly language
device driver. See Chapter 2.
EMMLIB A set of C-callable assembly language functions that call
the EMS driver directly. See Chapter 3.
These libraries allow you to use the full functionality of EMS without
spending countless hours writing assembly language programs.
This manual supplements the Lotus-Intel-Microsoft Expanded Memory
Specification manual (also referred to as the EMS manual). The LIM
specification defines the software interface between an application
program and the expanded memory used by the program.
How to use this book
--------------------
This manual explains the features and operation of the EMS Toolkit
libraries. Once you are familiar with the libraries and how to use
them, you can use this book as a quick reference for function names,
parameters, and error messages.
Here's what you'll find in each chapter of the manual: Chapter 1 -- Getting
Started: This is the chapter you're reading now. Besides introducing you
to the EMS Toolkit, this chapter lists the contents of the Intel diskettes,
offers suggestions for which library to use, and tells you how to install
the software.
Chapter 2 -- MEMLIB: Library for C Developers This chapter describes
how the MEMLIB library works, how to write code to use MEMLIB, and how to
compile and link MEMLIB. The last section (which makes up the bulk of this
chapter) describes each of the MEMLIB functions in detail.
Chapter 3 -- EMMLIB: Library for Assembly Language and C Developers
Chapter 3 describes the EMMLIB library and how it works, and describes how
to compile and link EMMLIB. This chapter also includes lists of EMMLIB
functions, and tells you how to get more information about each one.
Appendix A -- Example Progra: This short example program
demonstrates how to use MEMLIB to store and access data in expanded memory.
Appendix B -- Error Messages: This appendix lists the error messages
you may incur from MEMLIB, and suggests corrective actions.
Appendix C -- Technical Information About MEMLIB: This appendix explains
the more technical aspects of how MEMLIB allocates and frees expanded
memory. You don't need to know this information to use MEMLIB.
What's on the disks?
--------------------
The EMS Toolkit package includes four diskettes. You'll need disks 1, 2
and 3 to use either of the toolkit libraries. If you are an assembly
language developer and want to use expanded memory to execute code, you may
want to use disk 4. Disk 4 contains examples for assembly language
programmers only. (You don't need disk 4 to use MEMLIB or EMMLIB.)
The Intel EMS Toolkit diskettes contain the following files:
Disk 1
Filename Description
MEMLIB.C MEMLIB source code (functions)
MEMLIB.H MEMLIB include file (function prototypes)
MEMINTRL.C MEMLIB source code (internal MEMLIB utilities)
ERRORS.H MEMLIB error messages
EMMLIB.LIB EMM large-model library of C interface routines
EMMLIB.H EMMLIB include file
Disk 2
Filename Description
SAMPLE.C Short sample program using MEMLIB functions
SAMPLE.MAK "make" file for use with SAMPLE.C program
ROLODEX.C More detailed sample program using MEMLIB and EMMLIB
ROLODEX.H Header file for use with ROLODEX.C
ROLODEX.DAT Data file for ROLODEX.C
ROLODEX.MAK "make" file for use with ROLODEX.C program
EMMLIB <DIR> Directory containing EMMLIB function files
Disk 3
Filename Description
EMMLIB <DIR> Directory containing the rest of the EMMLIB function
files and other EMMLIB support files
Disk 4
Filename Description
LOADCODE.ASM Sample assembly language program that demonstrates how
to execute code from expanded memory
HELLO.ASM Sample code the LOADCODE.ASM will execute
LOADCODE.MAK "make" file for LOADCODE.ASM
Which library should I use?
---------------------------
The way in which your application will use expanded memory determines
which library you should use.
o If you are writing code in C and you want to store data in
expanded memory, you can use MEMLIB; it offers routines to do this
quickly and easily.
o If you understand the Lotus-Intel-Microsoft Expanded Memory
Specification and want to make expanded memory calls directly from C,
you must use EMMLIB. For example, if you want to use named handles for
the blocks of expanded memory you allocate, you need to use EMMLIB.
o If you want to use expanded memory for more complex uses such as
executing code, you must write your program in assembly language and
make EMS function calls directly.
Requirements
------------
The functions in the EMS Toolkit libraries assume a few things about
your computer's environment.
+
o Both MEMLIB and EMMLIB assume that Microsoft C version 5.1 and its
"include" files are available on your system.
o MEMLIB assumes that you are using a C "large-memory-model." EMMLIB
allows you to use any size memory model.
o The sample "make" files assume that the Microsoft utility MAKE.EXE
is available; that the source code, header files, and EMMLIB.LIB are
in one directory; and that the EMMLIB function files are in a
subdirectory named \EMMLIB. Intel recommends that you install the
MEMLIB files and your application's source code in the same
subdirectory.
Installing the software
-----------------------
The following sequence is the way we suggest you install the EMS
Toolkit software. For this example, suppose the application source code is
kept a subdirectory named \APP.
1 Insert Intel Toolkit diskette 1 into drive A.
2 At the DOS prompt, type the following:
XCOPY A:\*.* C:\APP /s
3 Repeat the first two steps with diskettes 2 and 3.
This command will copy the contents of the Intel disks to the \APP
directory on drive C.
/s means that all files in subdirectories below A:\ will be copied,
and will keep the same directory structure. (If you'd like more
information about the XCOPY command, refer to a DOS manual.)
Chapter 2
MEMLIB: LIBRARY FOR C DEVELOPERS
MEMLIB is a set of functions that allow developers to manage expanded
memory similar to the way they manage conventional memory with C.
MEMLIB functions look and act like some of the more familiar C functions
(malloc and free, for example).
MEMLIB's internal structure does the "housekeeping" necessary to access and
store data in expanded memory. When you use MEMLIB, you won't need to
worry about page frame size, 16K-byte boundaries, or interfacing with an
assembly language device driver.
MEMLIB lets you allocate and access any size block of memory up to 64K
bytes. It tracks available free memory, and uses a "best fit"
algorithm to allocate new blocks.
When you use MEMLIB, you just make a few C calls, and the libraries do
the rest.
Your application makes a call to MEMLIB, and MEMLIB in turn calls
the EMMLIB library to access expanded memory. EMMLIB then translates
the C calls into assembly language, and passes the calls on to the EMS
driver.
Compiling and linking MEMLIB
----------------------------
Because MEMLIB uses EMMLIB calls to perform its functions, you must
link and compile both libraries when you use MEMLIB. (The toolkit includes
a previously made EMMLIB.LIB file to use with MEMLIB.) You can compile
and link either with "make" (a Microsoft C utility) or manually.
Using the "make" file
---------------------
The easiest way to compile and link a number of interdependent modules
is to use a "make" file. A "make" file lists all of the modules and
their dependencies in a single file.
A "make" file for a program called "SAMPLE" to use MEMLIB should
contain the following lines.
(contents of the file sample.mak)
memlib.obj: memlib.c memlib.h errors.h emmlib.h
CL /C /AL memlib.c
sample.obj: sample.c memlib.h errors.h
CL /C /AL sample.c
sample.exe: sample.obj memlib.obj
link sample memlib,,, emmlib.lib
To use the "make" file, type the following line at the DOS prompt:
make sample.mak
If you change any file, just run the "make" file again to recompile
and relink.
Compile and link manually
-------------------------
Use the following command to compile the MEMLIB library:
CL /C /AL memlib.c
Use the following command to link MEMLIB to a program called "SAMPLE":
LINK sample memlib, sample, nul, emmlib.lib
Suggested sequence for using MEMLIB functions
---------------------------------------------
MEMLIB functions provide a convenient way for your application to
store data in expanded memory. To use expanded memory (and MEMLIB) most
effectively, your application should follow this sequence of actions:
1. Allocate memory efmalloc allocates a block of expanded memory
and returns a token (a block ID) to the application.
2. Access memory seteptrs uses the token returned by efmalloc to
access the blocks you allocated. Also set1eptr,
set2eptrs, set3eptrs.
3. Free memory effree frees previously allocated blocks of memory.
Also effreeall.
The other MEMLIB functions are provided for more specialized uses.
You don't need to use them to store data in expanded memory.
**CAUTION** Be sure to check the error codes that MEMLIB returns. If
you try to allocate and use expanded memory when EMM isn't
installed, you may lose data or overwrite some other area of
memory. To learn more about MEMLIB's error codes, read
Appendix B.
The next section describes all of the MEMLIB functions in detail. Each
description includes the purpose of the function, the calling sequence to
use, and a short example program.
The functions are listed in alphabetical order for easy reference. Below is
a complete list of the functions grouped according to the operations they
perform. To learn about a particular function, turn to the specified page.
Function Page
Allocating Memory
efmalloc 2-10
Accessing Memory
seteptrs 2-24
set1eptr 2-28
set2eptrs 2-30
set3eptrs 2-32
Freeing Memory
effree 2-6
effreeall 2-8
Other
ememavl 2-12
ememmax 2-14
emsize 2-16
push_context 2-21
pop_context 2-18
This is all you need to begin using MEMLIB to get expanded memory for your
application program. If you would like more detailed information about how
MEMLIB works, read Appendix C, Technical Information about MEMLIB.
EFFREE
------
PURPOSE
The effree function frees a block of memory that efmalloc had allocated.
Effree is analogous to the standard C function free.
**CAUTION** The expanded memory manager (MEMLIB) is NOT a part of DOS.
MEMLIB will not automatically free your allocated blocks when
you exit your application. Your application should free all
blocks during any kind of exit, including <CTL><BREAK> or
other error conditions. (See Function 6, effreeall.)
CALLING SEQUENCE
unsigned int status;
status = effree (token);
unsigned int token The token that efmalloc returned when it
allocated that block of memory. (input)
STATUS
PASSED (zero) The block is now free.
error (non-zero value) See Appendix B for descriptions of error codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
unsigned int token;
unsigned int status;
status = efmalloc (100, &token);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = effree (token);
if (status == PASSED)
/* Token is free, continue normal code */
else
/* error condition */
EFFREEALL
---------
PURPOSE
The effreeall function frees all expanded memory blocks, pages, and
handles effreeallallocated by your application. Effreeall is a convenient
function to use when you are ending your application.
**CAUTION** The expanded memory manager (MEMLIB) is NOT a part of DOS.
MEMLIB will not automatically free your allocated blocks when
you exit your application. Your application should free all
blocks during any kind of exit, including <CTL><BREAK> or
other error conditions.
CALLING SEQUENCE
unsigned int status;
status = effreeall ( );
STATUS
PASSED (zero) All blocks, handles, and pages are now free.
error (non-zero value) See Appendix B for descriptions of error codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
unsigned int status;
...
status = effreeall();
if (status == PASSED)
printf ("effreeall() successful");
else
/* error condition */
EFMALLOC
--------
PURPOSE
The efmalloc function is analogous to the standard C function malloc.
In the same way that malloc allocates conventional memory, the efmalloc
function allocates a block of memory from expanded memory pool. You can
allocate up to 64K bytes with a call to efmalloc.
There is one significant difference between malloc and efmalloc. A
call to malloc allocates memory and returns a pointer, giving you access to
that memory. Efmalloc allocates memory, but doesn't return a pointer.
Here's why: You can't access expanded memory the same way you access
conventional memory. You have to map a block of expanded memory into
the page frame before you can access it. Once you've mapped in a block,
you get a pointer to that block. With MEMLIB, you access a block using
the seteptrs function (also set1eptr, set2eptrs, and set3eptrs). See the
seteptrs function for more information about accessing expanded memory.
**NOTE** You must use the effree (or effreeall) function to free a block of
memory allocated with efmalloc.
CALLING SEQUENCE
unsigned int status;
status = efmalloc (size, &token);
unsigned int size The size (in bytes) desired for the memory
block. The size must be greater than zero.
(input)
unsigned int token An identifier assigned to the memory block
you've allocated. The token identifies that
memory block in subsequent calls to other
functions such as set1eptr. (output)
STATUS
PASSED (zero) The memory manager has allocated the block as
expanded memory.
error (non-zero value) See Appendix B for descriptions of error
codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
unsigned int size;
unsigned int status;
unsigned int token;
size = 100 * sizeof(int);
status = efmalloc (size, &token);
if (status == PASSED)
/* Continue normal code. We have allocated */
/* space to store 100 integer values. */
else
/* error condition */
EMEMAVL
-------
PURPOSE
The ememavl function computes the amount (in bytes) of expanded memory
available in your computer. The amount returned by ememavl is the total of
all expanded memory available -- it is not the largest contiguous block of
expanded memory (see ememmax).
CALLING SEQUENCE
unsigned int status;
status = ememavl (&size)
unsigned long size The amount of expanded memory (in bytes)
ememavl returns (output)
STATUS
PASSED (zero) The memory manager has returned the total amount of
expanded memory.
error (non-zero value) See Appendix B for descriptions of the error codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
unsigned int status;
unsigned long size;
status = ememavl (&size);
if (status == PASSED)
printf ("Exp. memory avail. = %lu bytes \n",
size);
else
/* error condition */
EMEMMAX
-------
PURPOSE
The ememmax function returns the size (in bytes) of the largest usable
ememmaxblock of expanded memory. Because blocks of free memory can be
fragmented, this amount may be smaller than the total amount of free
expanded memory.
CALLING SEQUENCE
unsigned int status;
status = ememmax (&size);
unsigned int size The number of bytes in the largest usable block of
expanded memory. (output)
STATUS
PASSED (zero) The memory manager has returned the size of the
largest usable block.
error (non-zero value) See Appendix B for descriptions of the error codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
unsigned int status;
unsigned int size;
status = ememmax (&size);
if (status == PASSED)
printf ("Largest block available = %u bytes \n",
size);
else
/* error condition */
EMSIZE
------
PURPOSE
The emsize function computes the size of a previously allocated block
of expanded memory. Identify the block using the token that efmalloc
returned emsizeafter allocating it.
CALLING SEQUENCE
unsigned int status;
status = emsize (token, &size);
unsigned int token Identifier for the block. (input)
unsigned int size The size of the block (in bytes). (output)
STATUS
PASSED (zero) The token was valid; the size is computed.
error (non-zero value) See Appendix B for descriptions of error
codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
unsigned int status;
unsigned int token;
unsigned int size;
status = efmalloc (200, &token);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = emsize (token, &size)
if (status == PASSED)
printf ("Size of block = %u bytes \n", size);
else
/* error condition */
POP_CONTEXT
-----------
PURPOSE
The pop_context function restores the context saved by the
push_context function.
**NOTE** When you call pop_context, you lose access to the blocks that
were mapped in at the time of the call.
CALLING SEQUENCE
unsigned int status;
status = pop_context( );
STATUS
PASSED (zero) The context of block ( ) is restored.
error (non-zero value) See Appendix B for descriptions of error codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
unsigned int status;
unsigned int token1;
unsigned int token2;
void *pointer1;
void *pointer2;
status = efmalloc (100, &token1);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = efmalloc (200, &token2);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = set1eptr (token1, &pointer1);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = push_context();
if (status != PASSED)
/* error condition */
else
/* save context for block 1 */
status = set1eptr (token2, &pointer2);
if (status != PASSED)
/* error condition */
else
/* context for block 2 is active -- */
/* can't access block 1 */
...
status = pop_context();
if (status != PASSED)
/* error condition */
else
/* context for block 1 is active -- */
/* can't access block 2 */
PUSH_CONTEXT
------------
PURPOSE
The push_context function provides a convenient way to make the context of
a mapped block available for later use. The context tells MEMLIB which
blocks are mapped into which physical pages. Push_context saves the
context, making it easy to restore access to whatever block(s) were mapped
in at the time of the call to push_context.
Restore the context you've "pushed" using the pop_context function
(see Function 12).
CALLING SEQUENCE
unsigned int status;
status = push_context( );
STATUS
PASSED (zero) The memory manager has pushed the context of the
block onto a stack.
error (non-zero value) See Appendix B for descriptions of error codes.
**NOTE** To save a context, MEMLIB needs to allocate a small amount of
conventional memory. MEMLIB allocates this memory dynamically--
allocating just enough memory to save the context at the time of
the call (usually less than 20 bytes).
EXAMPLE
#include "memlib.h"
#include "errors.h"
unsigned int status;
unsigned int token1;
unsigned int token2;
void *pointer1;
void *pointer2;
status = efmalloc (100, &token1);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = efmalloc (200, &token2);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = set1eptr (token1, &pointer1);
...
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = push_context();
if (status != PASSED)
/* error condition */
else
/* save context for block 1 */
...
status = set1eptr (token2, &pointer2);
if (status != PASSED)
/* error condition */
else
/* context for block 2 is active -- */
/* can't access block 1 */
...
status = pop_context();
if (status != PASSED)
/* error condition */
else
/* context for block 1 is active -- */
/* can't access block 2 */
SETEPTRS
--------
PURPOSE
The seteptrs function attempts to gain access to the blocks you specify.
Seteptrs then returns pointers to those blocks. Use this function if you
need access to more than three blocks at once. Use set1eptr, set2eptrs,
or set3eptrs to access 1, 2, or 3 blocks of memory.
You can access all allocated blocks, but not necessarily all at the same
time. You can access only that memory which is mapped into the page frame.
Each expanded memory page is 16K, so if your page frame is 64K bytes, it
will hold four pages, and any four blocks of 16K or less can be mapped in
at one time. (EMS page frames are guaranteed to be at least 64K bytes.)
If the combined size of all memory blocks you allocate during your
program's execution is less than the size of your page frame, you can
access all of the blocks at once.
For a more detailed description of page frames, read Chapter 1 in the EMS
manual.
**NOTE** Seteptrs will unmap any pages that were mapped in before the call
to seteptrs. If you want to call seteptrs, but want to regain access to a
block that had been mapped in before the call, use the push_context
function (before you call seteptrs). See push_context.
CALLING SEQUENCE
unsigned int status;
status = seteptrs (num_blocks, tokens, pointers);
unsigned int num_blocks The number of blocks you want to
access. (input)
unsigned int tokens[num_blocks] An array of tokens that efmalloc
returned when it allocated the
memory blocks. (input)
void *pointers[num_blocks] The array of pointers seteptrs
returns. Pointer[i] will point to
the block of memory identified by
token[i]. (output)
STATUS
PASSED (zero) You can gain access to all of the specified blocks.
error (non-zero value) See Appendix B for descriptions of error codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
unsigned int tokens[2];
/* Set array size for the number of blocks */
/* you wish to allocate (in this case, 2) */
void far *pointers[2];
unsigned int status;
status = efmalloc (200, &token[0]);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = efmalloc (600, &token[1]);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = seteptrs (2, tokens, pointers)
if (status == PASSED)
/* blocks are mapped in -- use */
/* pointers to reference them */
else
/* error condition */
SET1EPTR
--------
PURPOSE
The set1eptr function provides access to a single block of memory by
calling seteptrs. (This is a convenience routine for programmers who don't
want to declare the arrays required by seteptrs.)
CALLING SEQUENCE
unsigned int status;
status = set1eptr (token, &pointer);
unsigned int token The token that efmalloc returned when it
allocated that block of memory. (input)
void *pointer The pointer that set1eptr returns to the
application. (output)
STATUS
PASSED (zero) You have access to the block.
error (non-zero value) See Appendix B for descriptions of error codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
void *pointer;
unsigned int token;
unsigned int status;
status = efmalloc (500, &token);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = set1eptr (token, &pointer);
if (status == PASSED)
/* You have access to that block. Use */
/* the pointer as the block's reference. */
else
/* error condition */
SET2EPTRS
---------
PURPOSE
The set2eptrs function provides access to two blocks of expanded memory by
calling seteptrs. (This is a convenience routine for programmers who don't
want to declare the arrays required by seteptrs.)
CALLING SEQUENCE
unsigned int status;
status = set2eptrs (token1, token2, &pointer1, &pointer2);
unsigned int token1 The token efmalloc returned when it allocated
the first block of memory. (input)
unsigned int token2 The token efmalloc returned when it allocated
the second block of memory. (input)
void *pointer1 The pointer to the first block that set2eptrs
returns. (output)
void *pointer2 The pointer to the second block that set2eptrs
returns. (output)
STATUS
PASSED (zero) You have access to these two blocks.
error (non-zero value) See Appendix B for descriptions of error codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
void *pointer1;
void *pointer2;
unsigned int token1;
unsigned int token2;
unsigned int status;
status = efmalloc (500, &token1);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = efmalloc (900, &token2);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = set2eptrs (token1, token2, &pointer1, &pointer2);
if (status == PASSED)
/* You have access to these blocks. */
/* Use the pointers as references. */
else
/* error condition */
SET3EPTRS
---------
PURPOSE
The set3eptrs function provides access to three blocks of expanded memory
by calling seteptrs. (This is a convenience routine for programmers who
don't want to declare the arrays required by seteptrs.)
CALLING SEQUENCE
unsigned int status;
status = set3eptrs (token1, token2, token3, &pointer1, &pointer2, &pointer3);
unsigned int token1 The token efmalloc returned when it allocated
the first block of memory. (input)
unsigned int token2 The token efmalloc returned for the second
block. (input)
unsigned int token3 The token efmalloc returned for the third
block. (input)
void *pointer1 The pointer to the first block that set3eptrs
returns. (output)
void *pointer2 The pointer to the second block that set3eptrs
returns. (output)
void *pointer3 The pointer to the third block. (output)
STATUS
PASSED (zero) You can gain access to these three blocks.
error (non-zero value) See Appendix B for descriptions of error codes.
EXAMPLE
#include "memlib.h"
#include "errors.h"
void *pointer1;
void *pointer2;
void *pointer3;
unsigned int token1;
unsigned int token2;
unsigned int token3;
unsigned int status;
status = efmalloc (500, &tok1);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = efmalloc (900, &tok2);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
set3eptrs status = efmalloc (300, &tok3);
if (status != PASSED)
/* error condition */
else
/* continue normal code */
...
status = set3eptrs (token1, token2, token3,
&pointer1, &pointer2, &pointer3);
if (status == PASSED)
/* Blocks are allocated; use pointers as references */
else
/* error condition */
Chapter 3
EMMLIB: LIBRARY FOR ASSEMBLY LANGUAGE
AND C DEVELOPERS
EMMLIB is a collection of assembly language functions that call EMS
functions directly. This library provides full EMS capability to C
programmers; EMMLIB performs all of the functions listed in the
Lotus-Intel-Microsoft Expanded Memory Specification.
If you want to use expanded memory for more complex uses such as named
handles, alternate register sets, or page aliasing, then you will need the
advanced functions available from EMMLIB.
**NOTE** LIM-EMS is a powerful and complex specification. The EMMLIB
routines are designed to allow high level languages to use the full power
of EMM directly; the routines are not designed to simplify the
specification.
The LIM specification has approximately 30 functions, and most of these
functions have subfunctions. EMMLIB provides C-callable routines for all
of the functions and subfunctions (a total of 59). The EMMLIB functions
are described in comment headers in the .ASM files on the Intel diskettes.
Each filename includes the number of the EMS function corresponding to the
EMMLIB function.
Table 3-1 is a list of the functions available in EMMLIB, grouped according
to the operations they perform. The table includes the name of the
function, the file containing the code and description, and the
corresponding function number from EMS.
Table 3-2 lists the functions in alphabetical order, and includes cross
references to the filename and corresponding EMS function.
For a detailed description of a function, read the <Filename> file using
any text editor, or read the description of the corresponding assembly
language function <EMS Function No.> in the EMS manual.
For example, to map in a couple of pages of expanded memory, you could use
the map_unmap_pages function. To learn how to use this function, you would
read either file EMMLIB23.ASM or the description of Function 17 in the EMS
manual.
**NOTE** EMMLIB.H is a header file that provides your C code with all of
the "typedefs", function prototypes, and "#defines" that you need to call
the EMMLIB functions. Be sure to include this file when you use any EMMLIB
function.
Table 3-1 EMMLIB Functions grouped by operation
______________________________________________________________
Function Name Filename EMS Function No.
_____________________________________________________________
presence, status, and version
EMM_installed EMM01-B.ASM 1
get_EMM_status EMM01-A.ASM 1
get_EMM_version EMM07-A.ASM 7
memory allocation
get_unalloc_page_count EMM03-A.ASM 3
get_alloc_page_count EMM03-B.ASM 3
get_total_page_count EMM03-C.ASM 3
alloc_pages EMM04-A.ASM 4
dealloc_pages EMM06-A.ASM 6
realloc_pages EMM18-A.ASM 18
get_unalloc_raw_page_count EMM26-A.ASM 26
get_alloc_raw_page_count EMM26-B.ASM 26
get_total_raw_page_count EMM26-C.ASM 26
alloc_std_pages EMM27-A.ASM 27
alloc_raw_pages EMM27-B.ASM 27
mappable memory region information
get_page_frame_seg EMM02-A.ASM 2
get_mappable_conv_regions EMM25-A.ASM 25
get_mappable_exp_regions EMM25-A.ASM 25
get_mappable_regions EMM25-A.ASM 25
get_mappable_conv_region_count EMM25-A.ASM 25
get_mappable_exp_region_count EMM25-A.ASM 25
get_page_frame_count EMM25-A.ASM 25
get_mappable_region_count EMM25-C.ASM 25
memory mapping
map_unmap_page EMM05-A.ASM 5
map_unmap_pages EMM17-A.ASM 17
memory mapping context
save_context EMM08-A.ASM 8
restore_context EMM09-A.ASM 9
get_context EMM15-A.ASM 15
set_context EMM15-B.ASM 15
get_set_context EMM15-C.ASM 15
get_context_size EMM15-D.ASM 15
get_partial_context EMM16-A.ASM 16
get_partial_context_size EMM16-C.ASM 16
set_partial_context EMM16-B.ASM 16
memory movement and exchange
move_memory_region EMM24-A.ASM 24
xchg_memory_region EMM24-B.ASM 24
handle management
get_handle_count EMM12-A.ASM 12
get_handle_pages EMM13-A.ASM 13
get_all_handles_pages EMM14-A.ASM 14
get_handle_attrib EMM19-A.ASM 19
set_handle_attrib EMM19-B.ASM 19
get_attrib_capability EMM19-C.ASM 19
get_handle_name EMM20-A.ASM 20
set_handle_name EMM20-B.ASM 20
get_handle_dir EMM21-A.ASM 21
search_handle_name EMM21-B.ASM 21
get_total_handles EMM21-C.ASM 21
program flow control
alter_map_jump EMM22-A.ASM 22
alter_map_call EMM23-A.ASM 23
get_alter_map_call_stack_size EMM23-B.ASM 23
Operating System only
enable_OS_fcns EMM30-A.ASM 30
disable_OS_fcns EMM30-B.ASM 30
return_OS_access_key EMM30-C.ASM 30
get_hw_info EMM26-D.ASM 26
get_alt_reg_set EMM28-A.ASM 28
set_alt_reg_set EMM28-B.ASM 28
get_alt_context_size EMM28-C.ASM 28
alloc_alt_reg_set EMM28-D.ASM 28
dealloc_alt_reg_set EMM28-E.ASM 28
alloc_DMA_reg_set EMM28-F.ASM 28
enable_DMA_reg_set EMM28-G.ASM 28
disable_DMA_reg_set EMM28-H.ASM 28
dealloc_DMA_reg_set EMM28-I.ASM 28
prep_EMM_warmboot EMM29-A.ASM 29
_____________________________________________
Table 3-2 EMMLIB Functions in alphabetical order
________________________________________________________________
Function Name Filename EMS Function No.
_________________________________________________________________
alloc_alt_reg_set EMM28-D.ASM 28
alloc_DMA_reg_set EMM28-F.ASM 28
alloc_pages EMM04-A.ASM 4
alloc_std_pages EMM27-A.ASM 27
alloc_raw_pages EMM27-B.ASM 27
alter_map_jump EMM22-A.ASM 22
alter_map_call EMM23-A.ASM 23
dealloc_alt_reg_set EMM28-E.ASM 28
dealloc_DMA_reg_set EMM28-I.ASM 28
dealloc_pages EMM06-A.ASM 6
disable_DMA_reg_set EMM28-H.ASM 28
disable_OS_fcns EMM30-B.ASM 30
EMM_installed EMM01-B.ASM 1
enable_DMA_reg_set EMM28-G.ASM 28
enable_OS_fcns EMM30-A.ASM 30
get_all_handles_pages EMM14-A.ASM 14
get_alloc_page_count EMM03-B.ASM 3
get_alloc_raw_page_count EMM26-B.ASM 26
get_alt_context_size EMM28-C.ASM 28
get_alter_map_call_stack_size EMM23-B.ASM 23
get_alt_reg_set EMM28-A.ASM 28
get_attrib_capability EMM19-C.ASM 19
get_context EMM15-A.ASM 15
get_context_size EMM15-D.ASM 15
get_EMM_status EMM01-A.ASM 1
get_EMM_version EMM07-A.ASM 7
get_handle_count EMM12-A.ASM 12
get_handle_pages EMM13-A.ASM 13
get_handle_attrib EMM19-A.ASM 19
get_handle_name EMM20-A.ASM 20
get_handle_dir EMM21-A.ASM 21
get_hw_info EMM26-D.ASM 26
get_mappable_conv_regions EMM25-A.ASM 25
get_mappable_conv_region_count EMM25-A.ASM 25
get_mappable_exp_regions EMM25-A.ASM 25
get_mappable_exp_region_count EMM25-A.ASM 25
get_mappable_regions EMM25-B.ASM 25
get_mappable_region_count EMM25-C.ASM 25
get_page_frame_count EMM25-A.ASM 25
get_page_frame_seg EMM02-A.ASM 2
get_partial_context EMM16-A.ASM 16
get_partial_context_size EMM16-C.ASM 16
get_set_context EMM15-C.ASM 15
get_total_handles EMM21-C.ASM 21
get_total_page_count EMM03-C.ASM 3
get_total_raw_page_count EMM26-C.ASM 26
get_unalloc_page_count EMM03-A.ASM 3
get_unalloc_raw_page_count EMM26-A.ASM 26
map_unmap_page EMM05-A.ASM 5
map_unmap_pages EMM17-A.ASM 17
move_memory_region EMM24-A.ASM 24
prep_EMM_warmboot EMM29-A.ASM 29
realloc_pages EMM18-A.ASM 18
restore_context EMM09-A.ASM 9
return_OS_access_key EMM30-C.ASM 30
save_context EMM08-A.ASM 8
search_handle_name EMM21-B.ASM 21
set_alt_reg_set EMM28-B.ASM 28
set_context EMM15-B.ASM 15
set_handle_attrib EMM19-B.ASM 19
set_handle_name EMM20-B.ASM 20
set_partial_context EMM16-B.ASM 16
xchg_memory_region EMM24-B.ASM 24
_________________________________________________________
Appendix A
EXAMPLE PROGRAM
/* The intent of this example program is to show how to store and */
/* manipulate data in expanded memory using the C Memory Manager -- */
/* MEMLIB. */
/* */
/* This example shows what developers need to do in order to manipulate */
/* expanded memory in their own applications by using MEMLIB routines. */
/* For a more detailed program that uses a doubly linked list data */
/* structure, see the ROLODEX.C program. */
/* */
/* This program follows a seven-step algorithm: */
/* 1. Check the total amount of expanded memory available. */
/* 2. Find the largest contiguous block of free expanded memory. */
/* 3. Allocate expanded memory for two strings. */
/* 4. Calculate the size of the block allocated for the first string. */
/* 5. Print the two strings. */
/* 6. Manipulate the data by appending one string to the other. */
/* 7. Print the new string. */
/**************************************************************************/
#include <stdio.h>
#include <string.h>
/**************************************************************************/
/* The two header files below contain the function prototypes for */
/* MEMLIB routines and the error messages specific to MEMLIB. Keep in */
/* mind that MEMLIB calls EMMLIB functions, so you may get an error code */
/* relating to EMS. (EMS codes are explained in Table A-2 in the */
/* EMS manual.) You must include these two headers for any application */
/* that will use MEMLIB. If you are going to use any EMMLIB calls */
/* directly, you must also include "emmlib.h." */
/**************************************************************************/
#include "memlib.h"
#include "errors.h"
#define PASSED 0 /* If the MEMLIB call was successful */
/* it will return a zero. */
#define MAX_STRING_SIZE 255
void abort (unsigned short); /* If we encounter any errors, we */
/* call this function to "clean up." */
void main()
{
unsigned short status; /* The status after a MEMLIB call. */
char *string1; /* Our first data item. */
char *string2; /* Our second data item. */
unsigned int token1; /* The identifier to our first */
/* block of expanded memory. */
unsigned int token2; /* The identifier to our second */
/* block of expanded memory. */
unsigned int max_block_size; /* The size of the largest */
/* allocatable contiguous block. */
unsigned int size; /* The size of one of our blocks. */
unsigned long max_exp_mem; /* The amount of expanded mem avail. */
/***********************************************/
/* See how much total expanded memory we have. */
/***********************************************/
status = ememavl (&max_exp_mem);
if (status != PASSED)
{
printf ("Unable to obtain total expanded memory size.\n");
abort (status);
}
else
printf ("Total expanded memory available: %lu\n", max_exp_mem);
/*************************************************/
/* Get the size of the largest contiguous block. */
/*************************************************/
status = ememmax (&max_block_size);
if (status != PASSED)
{
printf ("Unable to obtain the largest contiguous block.\n");
abort (status);
}
else
printf ("Largest contiguous block: %u\n\n", max_block_size);
/*********************************************/
/* Allocate the memory and check for errors. */
/*********************************************/
status = efmalloc (MAX_STRING_SIZE, &token1);
if (status != PASSED)
{
printf ("Unable to allocate first block.\n");
abort (status);
}
else
printf ("Allocated space for the first block.\n");
status = efmalloc (MAX_STRING_SIZE, &token2);
if (status != PASSED)
{
printf ("Unable to allocate second block.\n");
abort (status);
else
printf ("Allocated space for the second block.\n\n");
/********************************/
/* Check the size of block one. */
/********************************/
status = emsize (token1, &size);
if (status != PASSED)
{
printf ("Unable to obtain size for block %u\n", token1);
abort (status);
}
else
printf ("Size of block %u is %u\n\n", token1, size);
/***********************************************/
/* Map in the two blocks, checking for errors. */
/***********************************************/
status = set2eptrs (token1, token2, & (char *) string1, & (char *)string2);
if (status != PASSED)
{
printf ("Unable to map in the two blocks.\n");
abort (status);
}
else
printf ("Blocks mapped in.\n\n");
printf ("Putting data in expanded memory.\n\n");
/*********************************************/
/* Store values in expanded memory using the */
/* pointers given to us from set2eptrs(). */
/*********************************************/
strcpy (string1, "'What if life is an illusion and nothing exists?'");
strcpy (string2, "'In that case, I definitely overpaid for my carpet.'
--Woody Allen");
printf ("String1: %s\n", string1);
printf ("String2: %s\n\n", string2);
/**************************************************/
/* Still using the pointers, manipulate the data. */
/**************************************************/
printf ("Manipulating data in expanded memory.\n");
strcat (string1, string2);
printf ("String1: %s\n\n", string1);
/**************************************************************/
/* Free all expanded memory we've allocated. If effreeall() */
/* is unsuccessful, we don't want to call abort() because */
/* abort() would just call effreeall() again. */
/**************************************************************/
status = effreeall();
if (status != PASSED)
{
printf ("Unable to free memory.\n");
printf ("ERROR %X\n", status);
exit (2);
}
else
printf ("Expanded memory freed.\n");
}
/****************************************************************************/
/* Aborts the program with an error message. Effreeall() frees all */
/* pages, blocks, and handles associated with this application. It is */
/* imperative that you release all the expanded memory you've allocated */
/* before exiting, so that other applications can use this memory. If */
/* you don't, you'll have to reboot to recover the lost memory. Notice */
/* also that a call to effreeall() checks the EMM status. In case that */
/* call fails, you'll get an error condtion back to let you know the */
/* memory was not freed. */
/* */
/* You should always call effreeall() before aborting your program, even */
/* if you get an error before allocating any memory. Effreeall() will free */
/* the handles and memory that MEMLIB allocated when it was initialized. */
/****************************************************************************/
void abort (status)
unsigned short status;
{
printf ("ERROR %X\n", status);
status = effreeall();
if (status != PASSED)
{
printf ("ERROR %X from effreeall().\n");
printf ("Expanded memory not freed.\n");
}
exit (1);
}
Appendix B
MEMLIB ERROR MESSAGES
This appendix lists the MEMLIB error codes that may appear when you are
running your application. The codes are listed in numerical order. Each
error code description includes:
o the hexadecimal number of the error code
o a one-line description of the error
o a short explanation of why the error message appeared
o what you should do to correct the error
Because MEMLIB makes calls to EMMLIB functions, you may see messages other
than those listed here. Each EMMLIB error message includes a hexadecimal
code number used by the Expanded Memory Specification (EMS). To find out
more about these errors, look up the code number in Table A-2, "Status and
Function Code Cross Reference," in the EMS manual.
Error:
0xD0 INVALID_TOKEN
cause The token that the MEMLIB routine received did not represent
an allocated block of memory.
action Each time efmalloc allocates a block of memory, it returns a
token unique to that block. Use this token when referring to
a particular block.
0xD1 NOT_ENOUGH_UNALLOCATED_PAGES
cause Your computer does not have enough free expanded memory.
MEMLIB requires at least 1 page (16K bytes) for its internal
directory, and assumes that you'll need at least 1 more page
to store data for your application.
action You need more expanded memory. Add more memory to your Above
Board, buy a Piggyback Option, or buy another Above Board.
0xD2 TOO_MANY_DIRECTORY_ENTRIES
cause You requested more separate blocks of memory than the MEMLIB
directory can handle. The maximum number of directory
entries available is 65535.
action Try requesting a few larger blocks instead of many small blocks.
0xD3 REQUEST_FOR_ZERO_LENGTH_BLOCK
cause You tried to allocate a 0K-byte block of memory.
action When you use efmalloc, make sure the size parameter is greater
than zero.
0xD4 CANNOT_MAP_ALL_BLOCKS
cause The blocks you attempted to access can't all be mapped into the
page frame at the same time.
action Try accessing fewer blocks at a time. See the NOTE at the
beginning of the seteptrs function for more information on
the number of memory blocks you can access.
0xD5 MAX_PUSH_CONTEXTS_EXCEEDED
cause MEMLIB has a set maximum number of contexts it will "push"
onto a stack, and you have exceeded that maximum.
(See Function 11 for more information about contexts.)
action You can either pop some of the contexts before pushing any
more, or you can change the maximum default. In the
MEMINTRL.C file you'll find a #define called
MAX_CONTEXTS_AVAILABLE. Increase this number, then recompile
MEMLIB.
0xD6 MALLOC_FAILURE
cause When you tried to push a context, MEMLIB could not find enough
open conventional memory to hold the context.
action Use the pop_context function to release the contexts you have
already pushed.
If you haven't called push_context previously but get this
error, you don't have enough free conventional memory to use
the push_context function. Unless you can free some of your
computer's conventional memory, don't call push_context or
pop_context.
0xD7 NO_CONTEXT_AVAILABLE_TO_POP
cause You attempted to call pop_context before calling push_context,
or you tried to pop a context you had popped already.
action Use the push_context function before using pop_context.
0xD8 ERROR_REALLOCATING_PAGES
cause Efmalloc could not allocate the block of memory you requested
because your computer doesn't have enough free expanded memory.
action Allocate a smaller block of memory, add more memory to your
Above Board, or buy another.
0xD9 NOT_INITIALIZED
cause You called a function that was designed to be called by another
function, not by your application.
action Limit your MEMLIB function calls to the functions listed in
this manual.
Appendix C
TECHNICAL INFORMATION ABOUT MEMLIB
This appendix explains in detail how MEMLIB provides access to expanded
memory, how it keeps track of expanded memory, how it allocates memory, and
the algorithms it uses. You don't need this information to use MEMLIB with
your application program. It's provided for your information only.
If you'd like more information about how expanded memory works, read
Chapter 1 in the EMS manual.
How MEMLIB provides access to expanded memory
---------------------------------------------
You can have up to 32M bytes of expanded memory in your computer, and
MEMLIB can provide access to all of it.
Expanded memory is divided into logical pages. Each logical page is 16K
bytes.
To access a block of expanded memory, MEMLIB needs to map in the logical
page that the block uses. MEMLIB can map only a limited number of these
pages into the EMS page frame at one time.
For example, if your page frame is 64K bytes, four logical pages can be
mapped into it. You can access four memory blocks at the same time if the
size of each block is 16K bytes or less. However, accessing five blocks at
once may be impossible, because the blocks might use five different logical
pages (five pages won't fit in the page frame).
How MEMLIB keeps track of expanded memory
-----------------------------------------
The expanded memory manager, MEMLIB, is based on a directory structure.
Each directory entry consists of four fields:
unsigned int token (0xFFFF = free, otherwise = allocated)
unsigned int size (size [in bytes] of this block)
unsigned short offset (the offset into the first logical page of
this block)
int logical_page[4] (pages used)
Blocks less than or equal to 16K bytes will use one logical page; 16 - 32K,
two pages; 32 - 48K, three pages; and 48 - 64K, four pages.
This directory is stored in expanded memory that MEMLIB allocates when
needed.
How MEMLIB allocates expanded memory
------------------------------------
To allocate memory, MEMLIB attempts to reuse as much deallocated memory as
possible before allocating any new blocks.
When a block of memory is freed, MEMLIB checks all other freed blocks to
see if they fall immediately before or after that block. If there are any
adjacent free blocks, MEMLIB combines the blocks into one larger block.
When a user requests a block of memory, MEMLIB checks all free blocks and
gives the user the smallest free block bigger than the size requested (best
fit). Any leftover memory is put into another free block.
EXAMPLE:
A user makes an efmalloc request for a 6K block. MEMLIB allocates
logical page 1 from EMM, and creates two directory entries: one to
the 6K block and one to the 10K free block.
Next, the user makes another efmalloc request, this time for an 11K
block. 11K won't fit in the 10K free block in logical page 1, and
will overlap into the next logical page if assigned to page 1 at all.
MEMLIB allocates an entirely new logical page, page 2. Again, it
creates one directory entry to point to the allocated block, and
another entry to point to the 5K of free memory (4).
Algorithms
----------
When a user requests a block of memory (efmalloc), Intel uses the following
algorithm:
(C pseudo code)
do
if (exact fit)
allocate block
else
check for best fit
while ((not exact fit) and (not last directory entry))
if (not exact fit)
if (best fit)
allocate block
set directory entry for remainder
else
request page from expanded memory manager
if request = OK
allocate block
else
return NOT_ENOUGH_UNALLOCATED_PAGES error
To free a block of memory (effree), we use this algorithm:
do
if (contiguous free block)
combine into one free block
while (not last directory entry)
if (no allocated pages found)
deallocate all pages /* prepare for program termination */
When mapping in blocks of memory (seteptrs), we use the following algorithm:
for (i = 0, i < number of requested blocks; i++)
if (logical pages needed for block i are already mapped)
OK = true
else
if (pages need for block i will fit)
OK = true
map in pages needed
else
return CANNOT_MAP_ALL_BLOCKS error